package MicroSpring.aopProxy.proxy.builder;

import MicroSpring.aopProxy.pjp.PjpImpl;
import MicroSpring.aopProxy.pjp.ProceedingJoinPoint;
import MicroSpring.aopProxy.proxy.ProxyFactory;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;

import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
/*
    生成cglib代理对象
 */
public class EnhancerBuilder implements ProxyFactory {
    private final Class clazz;
    private final Object targetBean;

    private final Set<String> targetMethodNames;
    private final Method adviceMethod;
    private final Object adviceBean;

    private final static int BEFORE=1;
    private final static int AFTER=2;
    private final static int AROUND=3;




    public EnhancerBuilder(Class clazz, Object targetBean,  Method adviceMethod, Object adviceBean) {
        this.clazz = clazz;
        this.targetBean = targetBean;
        this.targetMethodNames = new HashSet<>();
        this.adviceMethod = adviceMethod;
        this.adviceBean = adviceBean;
    }
    public EnhancerBuilder addTargetMethodMap(String methodName){
        this.targetMethodNames.add(methodName);
        return this;
    }
    public Object getBeforeProxyInstance() { return getProxyInstance(BEFORE); }

    public Object getAfterProxyInstance() {
        return getProxyInstance(AFTER);
    }
    public Object getAroundProxyInstance() {
        return getProxyInstance(AROUND);
    }

    /**
     * *
     * @param type :before,after,around
     *  获取三种类型cglib代理对象
     * @return
     */
    public Object getProxyInstance(int type){
        MethodInterceptor methodInterceptor=null;
        switch (type){
            case BEFORE:
                methodInterceptor= (proxy, method, args, methodProxy) -> {
                    if (targetMethodNames.contains(method.getName())){
                        adviceMethod.invoke(adviceBean,null);
                        return method.invoke(targetBean,args);
                    }else {
                        return method.invoke(targetBean,args);
                    }
                };
                break;
            case AFTER:
                methodInterceptor= (proxy, method, args, methodProxy) -> {
                    if (targetMethodNames.contains(method.getName())){
                        Object o = method.invoke(targetBean,args);
                        adviceMethod.invoke(adviceBean,null);
                        return o;
                    }else {
                        return method.invoke(targetBean,args);
                    }
                };
                break;
            case AROUND:
                methodInterceptor= (proxy, method, args, methodProxy) -> {
                    if (targetMethodNames.contains(method.getName())){
                        ProceedingJoinPoint pjp=new PjpImpl(method,targetBean,args);
                        return adviceMethod.invoke(adviceBean,pjp);
                    }else {
                        return method.invoke(targetBean,args);
                    }
                };
                break;
        }
        Object o = Enhancer.create(clazz, methodInterceptor);
        return o;
    }
}
